﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Cool.Core.ComDto;
using Cool.Core.Entities.System;
using Cool.Core.Enums;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;

namespace Cool.Core.Managers
{
    public class UserManager : IUserManager, IScoped
    {
        /// <summary>
        /// 用户仓储
        /// </summary>
        private readonly IRepository<SysUser> _userRepository;

        /// <summary>
        /// HttpContext 访问器
        /// </summary>
        private readonly IHttpContextAccessor _httpContextAccessor;

        /// <summary>
        /// 角色菜单配置仓储
        /// </summary>
        private readonly IRepository<SysRoleMenu> _roleMenuRepository;

        /// <summary>
        /// 菜单仓储
        /// </summary>
        private readonly IRepository<SysMenu> _menuRepository;

        /// <summary>
        /// 用户角色仓储
        /// </summary>
        private readonly IRepository<SysUserRole> _userRoleRepository;


        /// <summary>
        /// 功能仓储
        /// </summary>
        private readonly IRepository<SysRole> _roleRepository;

        /// <summary>
        /// 角色部门仓储
        /// </summary>
        private readonly IRepository<SysRoleDept> _roleDeptRepository;

        /// <summary>
        /// 缓存
        /// </summary>
        private readonly IMemoryCache _memoryCache;


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="httpContextAccessor"></param>
        /// <param name="userRepository"></param>
        /// <param name="memoryCache"></param>
        public UserManager(IHttpContextAccessor httpContextAccessor
            , IRepository<SysRole> roleRepository, IRepository<SysUser> userRepository
            , IMemoryCache memoryCache,
            IRepository<SysUserRole> userRoleRepository,
            IRepository<SysMenu> menuRepository,
            IRepository<SysRoleMenu> roleMenuRepository,
            IRepository<SysRoleDept> roleDeptRepository)
        {
            _httpContextAccessor = httpContextAccessor;
            _userRepository = userRepository;
            _memoryCache = memoryCache;
            _roleRepository = roleRepository;
            _userRoleRepository = userRoleRepository;
            _menuRepository = menuRepository;
            _roleMenuRepository = roleMenuRepository;
            _roleDeptRepository = roleDeptRepository;
        }
        
        public int UserId { get => 
            _httpContextAccessor.HttpContext.User.FindFirst("UserId")==null?
                0:
                int.Parse(_httpContextAccessor.HttpContext.User.FindFirst("UserId").Value);
        }
        public SysUser User { get => _userRepository.Find(UserId); }

        public List<SysRole> Roles { get => 
            (from userRole in _userRoleRepository.AsQueryable() 
            join role in _roleRepository.AsQueryable() on userRole.RoleId equals role.Id where userRole.UserId==UserId select role).ToList(); }
        public async Task<SysUser> CheckUserAsync(int userId, bool tracking = true)
        {
            // 查询用户是否存在
            var user = await _userRepository.FirstOrDefaultAsync(u => u.Id == userId, tracking);
            return user ?? throw Oops.Oh(SystemErrorCodes.u1002);
        }

        public List<string> GetSecuritiesAsync(int userId)
        {
            return _memoryCache.GetOrCreate($"{userId}_securities", (_) => 
                (from userRole in _userRoleRepository.AsQueryable()
                join roleMenu in _roleMenuRepository.AsQueryable() on userRole.RoleId equals roleMenu.RoleId
                join menu in _menuRepository.AsQueryable() on roleMenu.MenuId equals menu.Id
                select menu.Perms).ToList()
                );
        }
        public List<int> GetDeptCustomsByRoles()
        {
            return _roleDeptRepository.Where(d => Roles.Select(r => r.Id).ToList().Contains(d.RoleId)).Select(s => s.DeptId).ToList();
        }
    }
}
